/*
 *
 * Copyright (c) 2017, baiwang.com. All rights reserved.
 * All rights reserved.
 * Author: zhengb
 * Created: 2017/01/11
 * Description:
 *
 */

package com.shockweb.client;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import io.netty.channel.Channel;
/**
 * 客户端上下文，保存正在请求和返回的数据，并提供请求锁的功能
 * 
 * @author 彭明华
 * 2017年12月27日 创建
 */
public class ClientContext {

	/**
	 * 保存所有请求
	 */
    private final Map<String, Request> requests = new HashMap<String, Request>();
    
    /**
     * 当前类的读写锁
     */
    private final ReadWriteLock dataLock = new ReentrantReadWriteLock();
    

    
    /**
     * 保存客户端与通道的对应关系
     */
    private Channel channel = null;

    /**
     * 对uuid的请求加锁
     * @param uuid 唯一Id
     * @param timeOut 加锁的等待时间
     * @throws InterruptedException
     */
    public void lockWait(String uuid,long timeOut) throws InterruptedException{
    	Request req = null;
    	Object lock = null;
    	if(timeOut>0){
            try {
                dataLock.readLock().lock();
                if (requests.containsKey(uuid)) {
                	req = requests.get(uuid);
                	if(!req.returnValue){
                		lock = req.Lock;
                	}
                }
            } finally {
                dataLock.readLock().unlock();
            }
            if(req!=null && !req.returnValue){
                synchronized(lock){
                	lock.wait(timeOut);
                }
            }
    	}
    }
    
    /**
     * 加锁回复执行
     * @param uuid 唯一Id
     * @throws InterruptedException
     */
    public void lockResume(String uuid) throws InterruptedException{
    	Request req = null;
    	Object lock = null;
        try {
            dataLock.readLock().lock();
            if (requests.containsKey(uuid)) {
            	req = requests.get(uuid);
            	lock = req.Lock;
            }
        } finally {
            dataLock.readLock().unlock();
        }
        if(lock!=null){
            synchronized(lock){
            	lock.notifyAll();
            }
        }
        try {
            dataLock.writeLock().lock();
            if (req!=null) {
            	req.Lock = null;
            }
        } finally {
            dataLock.writeLock().unlock();
        }
    }
    
    /**
     * 初始化请求
     * @param uuid 唯一Id
     */
    public void init(String uuid) {
        try {
            dataLock.writeLock().lock();
            if (!requests.containsKey(uuid)) {
            	requests.put(uuid, new Request());
            }
        } finally {
            dataLock.writeLock().unlock();
        }
    }
    
    /**
     * 销毁uuid对应请求
     * @param uuid 唯一Id
     */
    public void destroy(String uuid) {
        try {
            dataLock.writeLock().lock();
            requests.remove(uuid);
        } finally {
            dataLock.writeLock().unlock();
        }
    }

    /**
     * 如果uuid请求在，则保存返回的数据
     * @param uuid 唯一Id
     * @param data 返回的数据
     */
    public void setData(String uuid, byte[] data) {
        try {
            dataLock.readLock().lock();
            if (requests.containsKey(uuid)) {
            	requests.get(uuid).data = data;
            	requests.get(uuid).returnValue = true;
            }
            
        } finally {
            dataLock.readLock().unlock();
        }
    }

    /**
     * 获取uuid对应的请求
     * @param uuid 唯一Id
     * @return
     */
    public Request getRequest(String uuid) {
        try {
            dataLock.readLock().lock();
            if (requests.containsKey(uuid)) {
            	return requests.get(uuid);
            }else{
            	return null;
            }
        } finally {
            dataLock.readLock().unlock();
        }
    }
    

    /**
     * 如果uuid请求在，则保存返回的异常
     * @param uuid
     * @param data
     */
    public void setException(String uuid, Throwable e) {
        try {
            dataLock.readLock().lock();
            if (requests.containsKey(uuid)) {
            	requests.get(uuid).exception = e;
            	requests.get(uuid).returnValue = true;
            }
        } finally {
            dataLock.readLock().unlock();
        }
    }


    /**
     * 返回异常信息
     * @param uuid
     * @return
     */
    public Throwable getException(String uuid) {
        try {
            dataLock.readLock().lock();
            if (requests.containsKey(uuid)) {
            	return requests.get(uuid).exception;
            } else {
                return null;
            }
        } finally {
            dataLock.readLock().unlock();
        }
    }
    

    /**
     * 获取客户端channel
     * @return
     */
    public Channel getChannel() {
        return channel;
    }

    /**
     * 设置客户端channel
     * @param channel
     */
    public void setChannel(Channel channel) {
    	this.channel = channel;
    }

}
